
// 判断是否为对象
const isObject = val => val !== null && typeof val === 'object';
// 判断是否为响应式对象
const convert = target => isObject(target) ? reactive(target) : target;

const hasOwnProperty = Object.prototype.hasOwnProperty;

const hasOwn = (target, key) => hasOwnProperty.call(target, key);

export function reactive (target) {
  if (!isObject(target)) return target;

  const handler = {
    get(target, key, receiver) {
      // 收集依赖
      // console.log('get', key)
      track(target, key)
      const result = Reflect.get(target, key, receiver)
      return convert(result)
    },
    set (target, key, value, receiver) {
      const oldValue = Reflect.get(target, key, receiver)
      let result = true;
      if (oldValue !== value) {
        value = Reflect.set(target, key, value, receiver)
        // 触发更新
        trigger(target, key)
        // console.log('set', key)
      }

      return result
    },
    deleteProperty(target, key) {
      const handKey = hasOwn(target, key)
      const reslut  = Reflect.deleteProperty(target, key);
      if (handKey, reslut) {
        // 触发更新
        trigger(target, key)
        // console.log('delete key', key)
      }
      return reslut
    }
  }

  return new Proxy(target, handler)
}

let activeEffect = null;

export function effect (callback) {
  activeEffect = callback;
  callback() // 收集依赖
  activeEffect = null;
}

let targetMap = new WeakMap();

export function track(target, key) {
  if (!activeEffect) return
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()))
  }

  dep.add(activeEffect)
}

export function trigger (target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;
  const dep = depsMap.get(key);
  if (dep) {
    dep.forEach(effect => {
      effect();
    });
  }
}

export function ref (raw) {
  // 判断是否为ref创建的对象
  if (isObject(raw) && raw.__v_isRef) return
  let value = convert(raw);
  const tempObj = {
    __v_isRef: true,
    get value() {
      track(tempObj, 'value')
      return value;
    },
    set value (newValue) {
      if (newValue !== value) {
        raw = newValue
        value = convert(raw)
        trigger(tempObj, 'value')
      }
    }
  }
  return tempObj;
}

export function toRefs(proxy) {
  const ret = proxy instanceof Array ? new Array(proxy.length
    ): {}
  
  for (const key in proxy) {
    ret[key] = toProxyRef(proxy, key)
  }
  return ret;
}

function toProxyRef(proxy, key) {
  const temp = {
    __v_isRef: true,
    get value() {
      return proxy[key]
    },
    set value(newValue) {
      proxy[key] = newValue
    }
  }
  return temp;
}

export function computed (getter) {
  const result = ref();
  effect(() => (result.value = getter()))
  return result;
}